package com.jieli.bt.att.ui.settings.log

import android.Manifest
import android.annotation.SuppressLint
import android.content.ContentValues
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.provider.MediaStore
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.jieli.bt.att.R
import com.jieli.bt.att.databinding.FragmentLogFileBinding
import com.jieli.bt.att.ui.common.basic.BasicFragment
import com.jieli.bt.att.ui.widget.decoration.CommonItemDecoration
import com.jieli.bt.att.ui.widget.dialog.TipsDialog
import com.jieli.bt.att.util.BluetoothUtil
import com.jieli.bt.att.util.FileUtil
import com.jieli.bt.att.util.PermissionUtil
import com.jieli.bt.att.util.ViewUtil
import com.jieli.bt.att.util.hide
import com.jieli.bt.att.util.show
import com.jieli.logcat.JL_Log
import com.mcxtzhang.swipemenulib.SwipeMenuLayout
import permissions.dispatcher.NeedsPermission
import permissions.dispatcher.OnPermissionDenied
import permissions.dispatcher.OnShowRationale
import permissions.dispatcher.PermissionRequest
import permissions.dispatcher.RuntimePermissions
import java.io.File
import java.io.FileInputStream
import java.io.IOException

/**
 * @author zqjasonZhong
 * @since 2024/11/6
 * @email zhongzhuocheng@zh-jieli.com
 * @desc 打印文件界面
 */
@RuntimePermissions
class LogFileFragment : BasicFragment() {

    companion object {
        fun newInstance() = LogFileFragment()
    }

    private lateinit var binding: FragmentLogFileBinding
    private lateinit var viewModel: LogFileViewModel
    private lateinit var adapter: LogFileAdapter

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        FragmentLogFileBinding.inflate(inflater, container, false).also {
            binding = it
            return it.root
        }
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        viewModel = ViewModelProvider(this)[LogFileViewModel::class]
        initUI()
        addObserver()
        viewModel.readLogFiles()
    }

    @Suppress("DEPRECATION")
    @Deprecated("Deprecated in Java")
    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        onRequestPermissionsResult(requestCode, grantResults)
    }

    @NeedsPermission(value = [Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE])
    fun readStoragePermissionAllow(filePath: String) {
        val hasReadPermission = PermissionUtil.hasReadStoragePermission(requireContext())
        val hasWritePermission = PermissionUtil.hasWriteStoragePermission(requireContext())
        JL_Log.d(
            TAG, "readStoragePermissionAllow", "hasReadPermission : $hasReadPermission, " +
                    "hasWritePermission : $hasWritePermission"
        )
        dismissPermissionTipsDialog()
        copyFileToDownloadFolder(filePath)
    }

    @OnShowRationale(value = [Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE])
    fun showRelationFromStoragePermission(request: PermissionRequest) {
        request.proceed()
    }

    @OnPermissionDenied(value = [Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE])
    fun onDeniedFromStoragePermission() {
        dismissPermissionTipsDialog()
        showTips(getString(R.string.missing_permission_desc))
    }

    private fun initUI() {
        binding.viewToolBar.tvTitle.text = getString(R.string.log_file)
        binding.viewToolBar.btnLeft.setOnClickListener { finish(100) }
        binding.viewToolBar.btnRight.setImageResource(R.drawable.ic_cleaning_black)
        binding.viewToolBar.btnRight.setOnClickListener {
            viewModel.clearLog()
        }

        adapter = LogFileAdapter()
        adapter.setOnItemClickListener { adapter, _, position ->
            val file = (adapter as LogFileAdapter).getItem(position)
            tryToOpenFile(file.path)
        }
        adapter.setOnItemChildClickListener { adapter, view, position ->
            val file = (adapter as LogFileAdapter).getItem(position)
            when (view.id) {
                R.id.btn_download -> {
                    if (FileUtil.isFileInDownload(requireContext(), file.name)) {
                        return@setOnItemChildClickListener
                    }
                    tryToDownloadFile(file.path)
                }

                R.id.btn_share -> {
                    tryToShareFile(file.path)
                }

                R.id.btn_remove -> {
                    viewModel.deleteFile(file.path)
                    adapter.getViewByPosition(position, R.id.main)?.let { itemView ->
                        if (itemView is SwipeMenuLayout) {
                            itemView.quickClose()
                        }
                    }
                }
            }
        }
        binding.rvLogFile.layoutManager = LinearLayoutManager(requireContext())
        binding.rvLogFile.adapter = adapter
        binding.rvLogFile.addItemDecoration(
            CommonItemDecoration(
                requireContext(),
                ContextCompat.getColor(requireContext(), R.color.line_color),
                RecyclerView.VERTICAL, ViewUtil.dp2px(requireContext(), 1)
            )
        )

        binding.viewToolBar.btnRight.hide()
    }

    private fun addObserver() {
        viewModel.logFilesMLD.observe(viewLifecycleOwner) {
            if (!isFragmentValid) return@observe
            adapter.setList(it)
            binding.viewToolBar.btnRight.apply {
                if (it.isEmpty()) {
                    hide()
                } else {
                    show()
                }
            }
        }
        viewModel.opResMLD.observe(viewLifecycleOwner) {
            if (!isFragmentValid || it.isSuccess()) return@observe
            val op = when (it.op) {
                LogFileViewModel.OP_DELETE_FILE -> getString(R.string.op_delete_file)
                LogFileViewModel.OP_DELETE_FOLDER -> getString(R.string.op_delete_folder)
                else -> it.op.toString()
            }
            showTips(
                BluetoothUtil.formatString(
                    "%s%s.\n%s: %d(0x%X), %s : %s.",
                    op,
                    getString(R.string.op_failed),
                    getString(R.string.err_code),
                    it.code,
                    it.code,
                    getString(R.string.err_msg),
                    it.message
                )
            )
        }
    }

    @SuppressLint("QueryPermissionsNeeded")
    private fun tryToOpenFile(filePath: String) {
        val file = File(filePath)
        if (!file.exists()) {
            showTips(getString(R.string.file_not_found))
            return
        }
        try {
            val uri = FileUtil.getUriByFile(requireContext(), file)
            Intent(Intent.ACTION_VIEW).apply {
                setDataAndType(uri, "text/plain")
                addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
            }.also { intent ->
                if (intent.resolveActivity(requireContext().packageManager) == null) {
                    showTips(getString(R.string.open_file_failed_by_other_app))
                    return
                }
                requireActivity().startActivity(intent)
            }
        } catch (e: Exception) {
            JL_Log.e(TAG, "tryToOpenFile", "exception : " + e.message)
            showTips(getString(R.string.open_file_exception))
        }
    }

    private fun tryToDownloadFile(filePath: String) {
        val hasReadPermission = PermissionUtil.hasReadStoragePermission(requireContext())
        val hasWritePermission = PermissionUtil.hasWriteStoragePermission(requireContext())
        JL_Log.d(
            TAG, "tryToDownloadFile", "hasReadPermission : $hasReadPermission, " +
                    "hasWritePermission : $hasWritePermission"
        )
        if (!hasReadPermission || !hasWritePermission) {
            showPermissionTipsDialog(getString(R.string.download_file_permission_tips))
            readStoragePermissionAllowWithPermissionCheck(filePath)
            return
        }
        copyFileToDownloadFolder(filePath)
    }

    private fun copyFileToDownloadFolder(filePath: String) {
        val file = File(filePath)
        if (!file.exists()) {
            showTips(getString(R.string.file_not_found))
            return
        }
        val value = ContentValues().apply {
            put(MediaStore.Downloads.DISPLAY_NAME, file.name)
            put(MediaStore.Downloads.MIME_TYPE, "text/plain")
            put(
                MediaStore.Downloads.RELATIVE_PATH,
                "${Environment.DIRECTORY_DOWNLOADS}/${FileUtil.DIR_BLUETOOTH_ATT}"
            )
        }
        val uri =
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                requireContext().contentResolver.insert(
                    MediaStore.Downloads.EXTERNAL_CONTENT_URI,
                    value
                )
            } else {
                FileUtil.getUriByPath(requireContext(), FileUtil.getDownloadFilePath(file.name))
            }
        uri?.let {
            copyFile(it, filePath)
        }
    }

    private fun copyFile(folderUri: Uri, filePath: String) {
        val file = File(filePath)
        if (!file.exists()) {
            showTips(getString(R.string.file_not_found))
            return
        }
        try {
            requireContext().contentResolver.openOutputStream(folderUri)?.let { outputStream ->
                val input = FileInputStream(file)
                val buffer = ByteArray(1024)
                var readSize: Int
                while (input.read(buffer).also { readSize = it } != -1) {
                    outputStream.write(buffer, 0, readSize)
                }
                outputStream.close()
                input.close()
            }
            val downloadFilePath = FileUtil.getDownloadFilePath(file.name).replace("/storage/emulated/0", "")
            showDownloadResultDialog(downloadFilePath)
            adapter.updateItemByFilePath(filePath)
        } catch (e: IOException) {
            JL_Log.e(TAG, "copyFile", "exception : " + e.message)
            showTips(getString(R.string.download_file_exception))
        }
    }

    private fun tryToShareFile(filePath: String) {
        val file = File(filePath)
        if (!file.exists()) {
            showTips(getString(R.string.file_not_found))
            return
        }
        try {
            val uri = FileUtil.getUriByFile(requireContext(), file)
            Intent(Intent.ACTION_SEND).apply {
                setType("text/plain")
                putExtra(Intent.EXTRA_STREAM, uri)
                addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
            }.also { intent ->
                requireActivity().startActivity(
                    Intent.createChooser(
                        intent,
                        getString(R.string.share_log_file)
                    )
                )
            }
        } catch (e: Exception) {
            JL_Log.e(TAG, "tryToShareFile", "exception : " + e.message)
            showTips(getString(R.string.share_file_exception))
        }
    }

    private fun showDownloadResultDialog(filePath: String) {
        if (!isFragmentValid) return
        TipsDialog.Builder()
            .title(getString(R.string.download_file_successful))
            .content(filePath)
            .confirmBtn { dialog, _ ->
                dialog.dismiss()
            }.apply { cancelable = false }.build()
            .show(childFragmentManager, "Download_Result")
    }
}